#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <pthread.h>

#include "threadpool.hpp"
#include "Inetaddr.hpp"
#include "lockguard.hpp"

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>

// class user
// {};
using task_t = std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    void Checkonlineuser(inetAddr &who)
    {
        lockGuard lockG(&_mutex);
        for(auto &user : _onlineUsers)
        {
            if (user == who)
            {
                LOG(DEBUG, "%s exists\n", who.addrStr().c_str());
                return;
            }
            
        }
        LOG(DEBUG, "%s does not exist, add it\n", who.addrStr().c_str());
        _onlineUsers.push_back(who);
    }

    void offline(inetAddr &who)
    {
        lockGuard lockG(&_mutex);
        auto it = _onlineUsers.begin();
        while(it != _onlineUsers.end())
        {
            if (*it == who)
            {
                LOG(DEBUG, "%s is offline\n", who.addrStr().c_str());
                _onlineUsers.erase(it);
                // 防止迭代器失效，找到对应的用户之后直接退出循环
                break;
            }
            it++;
        }
    }

    void auxi_forward(int socketfd, std::string message, inetAddr who)
    {
        lockGuard lockG(&_mutex);
        std::string sendMessage = "[" + who.addrStr() + "]# " + message;
        for(auto& user : _onlineUsers)
        {
            struct sockaddr_in peer = user.Addr();
            LOG(DEBUG, "Forward message to %s, message is %s\n", user.addrStr().c_str(), sendMessage.c_str());
            ::sendto(socketfd, sendMessage.c_str(), sendMessage.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
        }
    }

    void forward(int socketfd, const std::string message, inetAddr &who)
    {
        // 1.该用户是否在当前用户列表中，不在时再添加该用户到用户列表中
        Checkonlineuser(who);

        // 1.1 message == "QUIT" "Q"
        if (message == "QUIT" || message == "Q")
        {
            offline(who);
        }

        // 2. who一定再用户列表里
        // auxi_forward(socketfd, message);
        task_t t = std::bind(&Route::auxi_forward, this, socketfd, message, who);
        threadPool<task_t>::getInstance()->enqueue(t);
    }

    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }
private:
    // _onlineUsers实际上是一个公共资源
    // 为了防止有一些主机在发送消息的时候，其它主机在检查是否是在线用户
    std::vector<inetAddr> _onlineUsers;
    pthread_mutex_t _mutex;
};
